const fs = require('fs');
const path = require('path');
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generate = require('@babel/generator').default;
const t = require('@babel/types');

const targetDir = '/Users/xiaodian/Desktop/earth/src/components/SearchBlock';

function parseFile(filePath) {
  const code = fs.readFileSync(filePath, 'utf-8');
  return parser.parse(code, {
    sourceType: 'module',
    plugins: ['jsx', 'typescript'],
  });
}

function findFilesImportFormatMessage(dir) {
  const matchedFiles = [];

  function walk(dir) {
    fs.readdirSync(dir).forEach((file) => {
      const fullPath = path.join(dir, file);
      if (fs.statSync(fullPath).isDirectory()) {
        walk(fullPath);
      } else if (/\.(js|ts|tsx)$/.test(fullPath)) {
        const ast = parseFile(fullPath);
        let hasFormatMessageNamedImport = false;

        traverse(ast, {
          ImportDeclaration(path) {
            if (path.node.source.value === '@/utils/locale') {
              for (const specifier of path.node.specifiers) {
                if (
                  t.isImportSpecifier(specifier) && // 命名导入
                  specifier.imported.name === 'formatMessage'
                ) {
                  hasFormatMessageNamedImport = true;
                  break;
                }
              }
            }
          },
        });

        if (hasFormatMessageNamedImport) {
          matchedFiles.push(fullPath);
        }
      }
    });
  }

  walk(dir);
  return matchedFiles;
}

function transformFile(filePath) {
  const code = fs.readFileSync(filePath, 'utf-8');
  const ast = parser.parse(code, {
    sourceType: 'module',
    plugins: ['jsx', 'typescript'],
  });

  let hasReactIntlImport = false;
  let formatMessageLocalName = null;
  let hasChanged = false;

  traverse(ast, {
    ImportDeclaration(path) {
      if (path.node.source.value === '@/utils/locale') {
        const specifiers = path.node.specifiers;
        const newSpecifiers = [];

        specifiers.forEach((spec) => {
          if (
            t.isImportSpecifier(spec) &&
            spec.imported.name === 'formatMessage'
          ) {
            formatMessageLocalName = spec.local.name;
            hasChanged = true;
          } else {
            newSpecifiers.push(spec);
          }
        });

        if (newSpecifiers.length === 0) {
          path.remove();
        } else if (newSpecifiers.length !== specifiers.length) {
          path.node.specifiers = newSpecifiers;
        }
      }

      if (path.node.source.value === 'react-intl') {
        if (
          path.node.specifiers.some(
            (s) =>
              t.isImportSpecifier(s) &&
              s.imported.name === 'FormattedMessage'
          )
        ) {
          hasReactIntlImport = true;
        }
      }
    },

    CallExpression(path) {
      if (
        formatMessageLocalName &&
        t.isIdentifier(path.node.callee, { name: formatMessageLocalName }) &&
        path.node.arguments.length === 1
      ) {
        const arg = path.node.arguments[0];
        if (t.isObjectExpression(arg)) {
          let idProp = arg.properties.find(
            (p) =>
              t.isObjectProperty(p) &&
              t.isIdentifier(p.key, { name: 'id' })
          );
          let defaultProp = arg.properties.find(
            (p) =>
              t.isObjectProperty(p) &&
              t.isIdentifier(p.key, { name: 'default' })
          );

          if (idProp && t.isStringLiteral(idProp.value)) {
            const idValue = idProp.value.value;
            const attrs = [
              t.jsxAttribute(
                t.jsxIdentifier('id'),
                t.stringLiteral(idValue)
              ),
            ];

            if (defaultProp && t.isStringLiteral(defaultProp.value)) {
              attrs.push(
                t.jsxAttribute(
                  t.jsxIdentifier('defaultMessage'),
                  t.stringLiteral(defaultProp.value.value)
                )
              );
            }

            hasChanged = true;

            const jsx = t.jsxElement(
              t.jsxOpeningElement(t.jsxIdentifier('FormattedMessage'), attrs, true),
              null,
              []
            );

            path.replaceWith(jsx);
          }
        }
      }
    },
  });

  if (hasChanged && !hasReactIntlImport) {
    ast.program.body.unshift(
      t.importDeclaration(
        [
          t.importSpecifier(
            t.identifier('FormattedMessage'),
            t.identifier('FormattedMessage')
          ),
        ],
        t.stringLiteral('react-intl')
      )
    );
  }

  if (hasChanged) {
    const output = generate(ast, {}, code);
    fs.writeFileSync(filePath, output.code, 'utf-8');
    console.log(`Transformed: ${filePath}`);
  }
}

function main() {
  const files = findFilesImportFormatMessage(targetDir);
  console.log(`Found ${files.length} files importing named formatMessage.`);

  files.forEach(transformFile);
}

main();
